<?php

namespace JsonLowCode;

use BadMethodCallException;
use JsonLowCode\Helps\Random;
use JsonLowCode\Support\Fluent;
use Closure;

/**
 * @property array $states
 * @property array $methods
 * @property array $sourceList
 * @property array $maps
 * @property array $blocksData
 */
class PageCache extends Fluent
{
    public static ?PageCache $instance = null;

    protected array $cacheData = [];

    public function __construct()
    {
        parent::__construct();
        $this->states = [];
        $this->methods = [];
        $this->sourceList = [];
        $this->maps = [];
        $this->blocksData = [];
    }

    public static function make(): static
    {
        if (!self::$instance instanceof self) {
            self::$instance = new static();
        }
        return self::$instance;
    }

    /**
     * 设置页面states数据
     * @param string $key
     * @param mixed $value
     * @param string|null $cacheKey
     * @return $this
     */
    public function setState(string $key, mixed $value, string $cacheKey = null): static
    {
        if (str_contains($key,".")){
            if ($cacheKey){
                $states = $this->cacheData[$cacheKey]['states']??[];
            }else{
                $states = $this->states;
            }
            stateToNestedArray($states,$key,$value);
            return $this->setStates($states,$cacheKey);
        }else{
            return $this->setStates([$key=>$value],$cacheKey);
        }
    }

    /**
     * 设置页面states数据
     * @param array $states
     * @param string|null $cacheKey
     * @return $this
     */
    public function setStates(array $states, string $cacheKey = null): static
    {
        if ($cacheKey){
            $states = array_merge($this->cacheData[$cacheKey]['states']??[], $states);
            $this->cacheData[$cacheKey]['states'] = $states;
        }else{
            $states = array_merge($this->states,$states);
            $this->states = $states;
        }
        return $this;
    }

    /**
     * 获取页面states数据
     * @param string $key
     * @param string|null $cacheKey
     * @return mixed
     */
    public function getStates(string $key = "", string $cacheKey = null): mixed
    {
        if ($cacheKey){
            if (isset($this->cacheData[$cacheKey]['states'])){
                $states = $this->cacheData[$cacheKey]['states'];
                if ($key){
                    return $states[$key]??"";
                }else{
                    return $states;
                }
            }else{
                return [];
            }
        }
        if ($key){
            return $this->states[$key]??"";
        }
        return $this->states;
    }

    /**
     * 设置页面states数据
     * @param string $key
     * @param mixed $value
     * @param string|null $cacheKey
     * @return $this
     */
    public function setMethods(string $key, mixed $value, string $cacheKey = null): static
    {
        if ($cacheKey){
            $methods = $this->cacheData[$cacheKey]['methods']??[];
        }else{
            $methods = $this->methods;
        }
        if (isset($methods[$key])){
            throw new BadMethodCallException(sprintf(
                '页面方法 method: %s 已存在.', $key
            ));
        }
        $methods[$key] = ['key'=>$key,'value'=>$value];
        if($cacheKey){
            $this->cacheData[$cacheKey]['methods'] = $methods;
        }else{
            $this->methods = $methods;
        }
        return $this;
    }

    /**
     * 获取页面methods数据
     * @param string|null $cacheKey
     * @return array
     */
    public function getMethods(string $cacheKey = null): array
    {
        if ($cacheKey){
            return $this->cacheData[$cacheKey]['methods']??[];
        }
        return $this->methods;
    }

    /**
     * 设置page组件页面远程数据源
     * @param string $key 函数名
     * @param array|Axios $value
     * @param string|null $cacheKey
     * @return $this
     */
    public function setSourceList(string $key, array|Axios $value, string $cacheKey = null): static
    {
        if ($cacheKey){
            $sourceList = $this->cacheData[$cacheKey]['sourceList']??[];
        }else{
            $sourceList = $this->sourceList;
        }
        if (isset($sourceList[$key])){
            throw new BadMethodCallException(sprintf(
                '数据源sourceList: %s 已存在.', $key
            ));
        }
        $sourceList[$key] = $value;
        if ($cacheKey){
            $this->cacheData[$cacheKey]['sourceList'] = $sourceList;
        }else{
            $this->sourceList = $sourceList;
        }
        return $this;
    }


    /**
     * 获取页面methods数据
     * @param string|null $cacheKey
     * @return array
     */
    public function getSourceList(string $cacheKey = null): array
    {
        if ($cacheKey){
            return $this->cacheData[$cacheKey]['sourceList']??[];
        }
        return $this->sourceList;
    }


    /**
     * 设置组件映射
     * @param string $name
     * @param Map $map
     * @param string|null $cacheKey
     * @return $this
     */
    public function setMaps(string $name, Map $map, string $cacheKey = null): static
    {
        if ($cacheKey){
            $maps = $this->cacheData[$cacheKey]['maps']??[];
        }else{
            $maps = $this->maps;
        }

        if (isset($maps[$name])){
            throw new BadMethodCallException(sprintf(
                '组件映射的 maps: %s 已存在.', $name
            ));
        }
        $maps[$name] = $map;
        if ($cacheKey){
            $this->cacheData[$cacheKey]['maps'] = $maps;
        }else{
            $this->maps = $maps;
        }
        return $this;
    }

    /**
     * 获取页面maps数据
     * @param string|null $cacheKey
     * @return array
     */
    public function getMaps(string $cacheKey = null): array
    {
        if ($cacheKey){
            return $this->cacheData[$cacheKey]['maps']??[];
        }
        return $this->maps;
    }

    /**
     * 区块组件定义
     * @param string $name 组件名称
     * @param Closure $schema
     * @param string|null $cacheKey
     * @return $this
     */
    public function defineBlock(string $name, Closure $schema, string $cacheKey = null): static
    {
        if ($cacheKey){
            $blocksData = $this->cacheData[$cacheKey]['blocksData']??[];
        }else{
            $blocksData = $this->blocksData;
        }

        if (isset($blocksData[$name])){
            throw new BadMethodCallException(sprintf(
                '组件映射的 block: %s 已存在.', $name
            ));
        }
        $blocksData[$name] = ['label'=>$name,'content'=>UI::block()->componentName($name)->children($schema)];
        if ($cacheKey){
            $this->cacheData[$cacheKey]['blocksData'] = $blocksData;
        }else{
            $this->blocksData = $blocksData;
        }
        $this->cacheData[$cacheKey]['blocksData'] = $this->blocksData;
        return $this;
    }

    /**
     * 获取定义的区块组件列表
     * @param string|null $cacheKey
     * @return array
     */
    public function getDefineBlock(string $cacheKey = null): array
    {
        if ($cacheKey){
            if (isset($this->cacheData[$cacheKey]['blocksData'])){
                return array_values($this->cacheData[$cacheKey]['blocksData']);
            }
        }
        return array_values($this->blocksData);
    }

}
